﻿#include "pch.h"
#include <ShlObj.h>
#include <fstream>
#include <common/Exception.h>
#include <common/memory.h>

HRESULT TOAPI JOUI::UIreadFile(LPCWSTR filePath, LPVOID& retData, size_t& retSize)
{
    CHECK_PARAM(filePath);

    //打开文件
    std::fstream fs(filePath, std::ios::in | std::ios::binary);
    handle_if_false(fs.is_open(), EE_IO, L"打开文件失败");

    //获取文件大小
    fs.seekg(0, std::ios::end);
    size_t size = fs.tellg();

    //申请内存
    uint8_t* data = (uint8_t*)exalloc(size);
    handle_if_false(data, E_OUTOFMEMORY, L"申请数据块内存失败");

    try
    {
        //读取文件
        fs.seekg(0, std::ios::beg);
        throw_if_false(fs.read((char*)data, size), EE_IO, L"读取文件失败");

        //设置到数据块
        retData = data;
        retSize = size;
        return S_OK;
    }
    catch_default({});
}

HRESULT TOAPI JOUI::UIWriteFile(LPCWSTR file, const LPVOID data, size_t size)
{
    CHECK_PARAM(file);

    //打开文件
    std::fstream fs(file, std::ios::out | std::ios::binary | std::ios::trunc);
    handle_if_false(fs.is_open(), EE_IO, L"打开文件失败");

    //如果数据为空，则直接关闭文件
    if (data == nullptr || size == 0) {
        fs.close();
        return S_OK;
    }

    //写入文件
    handle_if_false(fs.write((const char*)data, size), EE_IO, L"写入文件失败");
    return S_OK;
}

HRESULT TOAPI JOUI::UIGetFileSize(LPCWSTR file, size_t& r_size)
{
    CHECK_PARAM(file);

    //打开文件
    std::fstream fs(file, std::ios::in | std::ios::binary);
    handle_if_false(fs.is_open(), EE_IO, L"打开文件失败");

    //获取文件大小
    fs.seekg(0, std::ios::end);
    r_size = fs.tellg();
    return S_OK;
}

BOOL TOAPI JOUI::UIfileOpenDlg(HWND hWnd, BOOL bOpenFileDialog, LPCWSTR lpszFilter, LPCTSTR lpszDefExt, LPCWSTR lpszFileName, LPCWSTR* retstrFile)
{
    BOOL rel = FALSE;
    OPENFILENAME m_ofn;
    BOOL m_bOpenFileDialog = bOpenFileDialog;// TRUE for file open, FALSE for file save
    TCHAR m_szFileTitle[_MAX_FNAME]{}; // contains file title after return
    TCHAR m_szFileName[128 * 1024]{};   // contains full path name after return
    DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
    if (m_bOpenFileDialog)
    {
        dwFlags = OFN_ALLOWMULTISELECT | OFN_EXPLORER;
    }

    std::wstring lpstrFilter = L"所有文件|*.*||";
    if (lpszFilter != NULL)
        lpstrFilter = lpszFilter;
    // 使用循环遍历字符串，并替换字符
    for (size_t i = 0; i < lpstrFilter.length(); i++) {
        if (lpstrFilter[i] == '|') {
            lpstrFilter[i] = '\0';
        }
    }


    memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
    m_szFileName[0] = _T('\0');
    m_szFileTitle[0] = _T('\0');

    m_ofn.lStructSize = sizeof(m_ofn);
    m_ofn.lpstrFile = m_szFileName;
    m_ofn.nMaxFile = sizeof(m_szFileName);
    m_ofn.lpstrDefExt = lpszDefExt;
    m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
    m_ofn.nMaxFileTitle = _MAX_FNAME;
    m_ofn.Flags = dwFlags;
    m_ofn.lpstrFilter = lpstrFilter.c_str();
    m_ofn.hwndOwner = hWnd;

    // setup initial file name
    if (lpszFileName != NULL)
        _tcscpy_s(m_szFileName, _countof(m_szFileName), lpszFileName);
    if (m_bOpenFileDialog)
    {
        if (GetOpenFileNameW(&m_ofn))
        {
            std::wstring filePath(m_szFileName);
            std::vector<std::wstring> fileNames;
            std::wstring str;
            wchar_t* p = m_szFileName + filePath.length() + 1;
            size_t folderPathLength = wcslen(p);
            if (folderPathLength == 0)
            { // 单个文件选择
                *retstrFile = StrDupW(filePath.c_str());
            }
            else
            {
                while (*p) {
                    std::wstring fileName(p);
                    fileNames.emplace_back(fileName);

                    p += fileName.length() + 1;
                }
                INT sn = 0;
                for (const auto& fileName : fileNames) {
                    std::wstring completePath = filePath + L"\\" + fileName;
                    if (sn > 0)
                    {
                        str += L"|" + completePath;
                    }
                    else
                    {
                        str += completePath;
                    }
                    sn++;
                }
                *retstrFile = StrDupW(str.c_str());
            }
            rel = TRUE;
        }
    }
    else
    {
        if (GetSaveFileNameW(&m_ofn))
        {
            *retstrFile = StrDupW(m_szFileName);
            rel = TRUE;
        }
    }
    return rel;
}

BOOL TOAPI JOUI::UIfileOpenFolder(HWND hWnd, LPCWSTR lpszTitle, LPCWSTR* retstrFile)
{
    TCHAR szPath[MAX_PATH];		//存放选择的目录路径
    BROWSEINFO bi;
    bi.hwndOwner = hWnd;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = szPath;
    bi.lpszTitle = lpszTitle;
    bi.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;//有新建文件夹按钮
    bi.lpfn = NULL;
    bi.lParam = 0;
    bi.iImage = 0;
    //弹出选择目录对话框
    LPITEMIDLIST lp = SHBrowseForFolder(&bi);

    if (lp)
    {
        if (SHGetPathFromIDList(lp, szPath))
        {
            *retstrFile = StrDupW(szPath);
            return TRUE;
        }
    }
    return FALSE;
}
